 /**
  Copyright [2008] [Raghunath N] Licensed under the Apache License, Version
  2.0 (the "License"); you may not use this file except in compliance with the License.
  You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
  Unless required by applicable law or agreed to in writing, software distributed under
  the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
  ANY KIND, either express or implied. See the License for the specific language
  governing permissions and limitations under the License.
 * gwt-greflection
 *
 * Copyright(c) 2008 
 *
 * visumagic@gmail.com
 * 
 *
 *  @author Raghunath N
 *
 */
package com.rn.gwt.reflect.gen;

import java.io.PrintWriter;



import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.PropertyOracle;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JField;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import com.rn.gwt.client.lang.reflect.GField;


public class RGenerator extends Generator {


	
	JField fields[]=null;
	String simpleClassName = null;
	String proxyClassName;
	public String generate(TreeLogger logger, GeneratorContext context, String typeName) throws UnableToCompleteException {
		try{
		
			
			PropertyOracle properties = context.getPropertyOracle();
			
		
			TypeOracle typeOracle = context.getTypeOracle();
			
			// Load the class/interface we are interested in through the typeOracle into the JClassType object 
			JClassType requestedClass = typeOracle.getType(typeName);
			
			// Get the package name of the class/interface
			String packageName = requestedClass.getPackage().getName();
			
			// Get the name of the class/interface
			simpleClassName=requestedClass.getSimpleSourceName();
			fields=requestedClass.getFields();
			// Our return class will have the same name as the original 
			// class with the word Proxy appended to it 
			 proxyClassName = simpleClassName + "Proxy" ;//+ version;
			
			// The new Qualified Class Name will indicate the new class will 
			// be in the same package as the original class with our new name
			String qualifiedProxyClassName = packageName + "." + proxyClassName;
			
			// Get the full qualified class name of the original class
			String qualifiedSourceName = requestedClass.getQualifiedSourceName();
			
			// Now we get a SourceWriter object for our new class
			SourceWriter writer = getSourceWriter(logger, context, packageName,
					proxyClassName, qualifiedSourceName);
						
			// And then write to the logger that we are starting the rewriting.
			logger.log(TreeLogger.INFO, "Starting rewriting using: "+this.getClass().getSimpleName()+" for "+1+" version", null);
			
			// If the SourceWriter object is null, then the new class that we are trying 
			// to create already exists, therefore we just need to return back 
			// the name of the new class
			if(writer==null){
				logger.log(TreeLogger.INFO, "Cancelled rewriting - class alredy exists", null);
				return qualifiedProxyClassName;
			} else {
				// The SourceWriter object was not null, therefore we have a 
				// reference to the new class that we will be building.
				
				// The first task is to override the old class' getName() method
				writeConstructor(logger,simpleClassName, writer);
				
				// Then we override the old class' createOptionsMenu() method
			
								
				// If all went well, then we commit the changes to our new class
				writer.commit(logger);
				
				// and tell the logger that we are complete
				logger.log(TreeLogger.INFO, "Completed rewriting", null);
			
				// To finish, we return the name of the new class
				return qualifiedProxyClassName;
			}
		} catch (NotFoundException e) {
			// We cannot find the class that we are looking for, so we cannot rewrite it
			logger.log(TreeLogger.ERROR, "Class '" + typeName + "' Not Found", e);
			throw new UnableToCompleteException();
		} 
	} 
	

	protected SourceWriter getSourceWriter(TreeLogger logger, GeneratorContext context,String packageName, 
			String className, String superclassName){
		PrintWriter printWriter = context.tryCreate(logger,packageName, className);
			if (printWriter == null) return null;
		
	
		ClassSourceFileComposerFactory composerFactory =new ClassSourceFileComposerFactory(packageName, className);
		
	
		composerFactory.addImport("com.rn.gwt.client.lang.*");
		composerFactory.addImport("com.rn.gwt.client.lang.reflect.*");
		composerFactory.addImport("com.google.gwt.user.client.Window");
		
		
			composerFactory.setSuperclass("GClass");
		
		return composerFactory.createSourceWriter(context, printWriter);
	}

	
	public void writeMembers(TreeLogger logger,String className, SourceWriter writer){
		logger.log(TreeLogger.INFO, "Writing writeMembers method for: "+className, null);
	
	}
	private final static String DCOT="\"";
	public void writeConstructor(TreeLogger logger,String className, SourceWriter writer){
		logger.log(TreeLogger.INFO, "Writing writeConstructor method for: "+className, null);
		writer.println("public "+proxyClassName+"()");
		writer.println("{");
	writer.println("this.name="+DCOT+className+DCOT+";");
		for (int i = 0; i < fields.length; i++) {
			writer.println("this.fields.put("+DCOT+fields[i].getName()+DCOT+"," +
					"new GField(){" );
				writer.println(	"public GField init()" +
					"{" +
					"init("+
									DCOT+fields[i].getName()+DCOT+","+
									DCOT+className+DCOT+","+
									"-1"+","+
									"-1"+","+
									DCOT+"signature"+DCOT+");" +
//					
					"return this;" +
					"};");
//	
//		
		writer.println("");
		writer.indent();
	writer.println("public Object get(Object obj){" +
				"return (("+simpleClassName+")obj)."+fields[i].getName()+";"+
			"}");
		
		writer.println("}" +
		");" );
		}
		writer.println(	"}" +
		"");
		
	}

	public void writeClassNameMethod(TreeLogger logger,String className, SourceWriter writer){
		
	} 
	
}